package TDAMapeo;

import TDALista.PositionList;
import TDALista.SLista;

//import GrafosNDConMatris.Arco;
//import TDALista.PositionList;




public class MapeoHashCerrado<K,V> implements Mapeo<K,V> {
protected Entrada<K,V> [] arreglo;
protected int cantBuckets;
protected int size;

public MapeoHashCerrado(int buckets)
{
	cantBuckets=buckets;
	arreglo=new Entrada[buckets];
	size=0;
		
}
	public int size() {
		
		return size;
	}


	public boolean isEmpty() {
		
		return size==0;
	}
	
	
	public Entrada<K,V> [] getArray(){
		return arreglo;
	}
	
    

	public V Recuperar(K key) throws InvalidKeyException {
	if(key==null)
		throw new InvalidKeyException("La Clave buscada es invalida");
	int i=Math.abs(key.hashCode()%this.cantBuckets);
	Entry<K,V>e=null;
	
			int j=i;
			do
			{
				e=arreglo[j%cantBuckets];
				if(e==null)
					return null;
				if(e.getKey().equals(key))
					return e.getValue();
				j++;
			}while(i!=(j%this.cantBuckets));
		
	
		return null;
	}

	public V Insertar(K key, V value) throws InvalidKeyException {
		if(key==null)
			throw new InvalidKeyException("Clave invalida, no se puede insertar. ");
		if(this.size()==this.cantBuckets)
			this.rehash();
		int i =Math.abs(key.hashCode()%this.cantBuckets);
		Entry<K,V>e=arreglo[i];
		int l=0;
		int j=i;
		int aux=-1;
		do{
			e=arreglo[(j%this.cantBuckets)];
			if(e==null)
			{
				arreglo[j]=new Entrada<K,V>(key,value);
				size++;
				return null;
			}
			if((e.getKey()!=null)&&(e.getKey().equals(key)))
			{
				V aR= e.getValue();
				arreglo[j]=new Entrada<K,V>(key,value);
				return aR;
			}
			if((e.getKey()==null)&&(aux==-1))
				aux=(j%this.cantBuckets);
			j++;
			l=(j%this.cantBuckets);
			}while(i!=l);
		if(aux>-1)
		{
			arreglo[aux]=new Entrada<K,V>(key,value);
			size++;
		}
		
		
		return null;
	}

	private void rehash(){
		
		Entrada<K,V> [] arreNEW=new Entrada[cantBuckets*2];
		Entrada<K,V> [] arreOLD=arreglo;
		int cantOLD=cantBuckets;
		arreglo=arreNEW;
		cantBuckets=cantBuckets*2;
		size=0;
		
		for(int i=0;i<cantOLD;i++)
		{
			try {
				this.Insertar(arreOLD[i].getKey(),arreOLD[i].getValue());
				arreOLD[i]=null;
			} catch (InvalidKeyException e) {}
		}
		arreOLD=null;
	}

	public V Eliminar(K key) throws InvalidKeyException
	{
		if(key==null)
			throw new InvalidKeyException("No se puede eliminar. La clave es incorrecta. ");
		int i = Math.abs(key.hashCode()%cantBuckets);
		Entry<K,V>e=null;
			int j=i;
			do
			{
				e=arreglo[j];
				if(e==null)
					return null;
				if((e.getKey()!=null)&&(e.getKey().equals(key)))
				{
					V aR= e.getValue();
					arreglo[j]=new Entrada<K,V>(null,null);
					size--;
					return aR;
				}
				j++;
				
			}while (i!=(j%cantBuckets));
		
	
		return null;
	}

	public Iterable<K> Claves() {
	
		Entry<K,V>e;
		PositionList<K>l=new SLista<K>();
		for(int i=0;i<arreglo.length;i++)
		{
			e=arreglo[i];
			if((e!=null)&&(e.getKey()!=null))
				l.addLast(e.getKey());
			
		}
		return l;
	}


	public Iterable<V> Valores() {
		Entry<K,V>e;
		PositionList<V>l=new SLista<V>();
		for(int i=0;i<arreglo.length;i++)
		{
			e=arreglo[i];
			if((e!=null)&&(e.getKey()!=null))
				l.addLast(e.getValue());
			
		}
		return l;
	}


	public Iterable<Entry<K, V>> Entries() {
		Entry<K,V>e;
		PositionList<Entry<K,V>>l=new SLista<Entry<K,V>>();
		for(int i=0;i<arreglo.length;i++)
		{
			e=arreglo[i];
			if((e!=null)&&(e.getKey()!=null))
				l.addLast(e);
			
		}
		return l;
	}
	

}
